package gameManager;

import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ImageIcon;

/**
 * A GameCharacter is essentially any moving object that can
 * collide with other objects.
 */
public abstract class GameCharacter implements Interactable {
    private String myName;
    private Point myPosition;
    private int myDirection;
    private int mySpeed;
    private Image myImage;
    private int myHealth;
    private List<WeaponObject> myWeapons = new ArrayList<WeaponObject> ();
    private List<String> NamesOfObjectsCanCollideWith = new ArrayList<String> ();
    private Dimension mySize;

    /**
     * Update method, moves the GameCharacter and then checks if its
     * weapons should be updated.
     * @param trigger the current time
     */
    public void update(int trigger) {
        move();
        updateWeapons(trigger);
    }

    /**
     * Updates the current position of the GameCharacter.
     */
    public void move() {
        int dx = (int) Math.round(Math.cos(getDirection() * Math.PI / 180 )*getSpeed());
        int dy = (int) Math.round(Math.sin(getDirection() * Math.PI / 180 )*getSpeed());

        getInteractablePosition().translate(dx, dy);
    }

    /**
     * Returns the current speed.
     */
    public int getSpeed(){
        return mySpeed;
    }

    /**
     * Sets the speed.
     * @param speed the new speed
     */
    public void setSpeed (int speed) {
        mySpeed = speed;
    }

    /**
     * Returns the position.
     */
    public Point getInteractablePosition() {
        return myPosition;
    }

    /**
     * Sets the position to newPosition.
     */
    public void setInteractablePosition(Point newPosition) {
        myPosition = newPosition;
    }

    /**
     * Returns the name of the GameCharacter.
     */
    public String getNameOfInteractable(){
        return myName;
    }

    /**
     * Sets the name to newName.
     * @param newName the new name
     */
    public void setNameOfInteractable(String newName) {
        myName = newName;
    }

    /**
     * Adds a the name of a new object that can be collided with.
     * @param newCollisionObject the name of the object to be added.
     */
    public void addCollisionObject(String newCollisionObject){
        if (!NamesOfObjectsCanCollideWith.contains(newCollisionObject)) {
            NamesOfObjectsCanCollideWith.add(newCollisionObject);
        }
    }

    /**
     * Sets the direction of movement to newDirection.
     * @param newDirection
     */
    public void setDirection(int newDirection){
        myDirection = newDirection;
    }

    /**
     * Changes the direction by dDirection.
     * @param dDirection
     */
    public void updateDirection(int dDirection){
        myDirection += dDirection;
    }

    /**
     * Returns the current direction.
     * @return
     */
    public int getDirection(){
        return myDirection;
    }
    
    /**
     * Sets the health to newHealthValue.
     * @param newHealthValue
     */
    public void setHealthValue(int newHealthValue) {
        myHealth = newHealthValue;
    }

    /**
     * Returns the current health value.
     * @return
     */
    public int getHealthValue(){
        return myHealth;
    }

    /**
     * Changes the health by dHealthValue.
     * @param dHealthValue
     */
    public void changeHealthValue (int dHealthValue){
        myHealth += dHealthValue;
    }

    /**
     * Sets the object image to a new file path.
     * @param imageFilePath
     */
    public void setObjectImage(String imageFilePath) {
        ImageIcon objectIcon = new ImageIcon(imageFilePath);
        myImage = objectIcon.getImage();
    }

    /**
     * Returns the current image.
     */
    public Image getObjectImage(){
        return myImage;
    }

    /**
     * Adds a new weapon to the GameCharacter.
     * @param newWeapon
     */
    public void addNewWeapon (WeaponObject newWeapon) {
        myWeapons.add(newWeapon);
    }

    /**
     * Returns a list of all weapons the GameCharacter currently has.
     * @return
     */
    public List<WeaponObject> getMyWeapons(){
        return myWeapons;
    }

    /**
     * Updates the cool down time of each weapon the GameCharacter
     * currently has.
     * @param trigger
     */
    public void updateWeapons (int trigger){
        for (WeaponObject weapon : myWeapons) {
            weapon.updateCoolDownWaitingTime(trigger);
        }
    }

    /**
     * Removes an objects from the list of collidable objects.
     * @param oldCollisionObject
     */
    public void removeCollisionObject(String oldCollisionObject) {
        if (NamesOfObjectsCanCollideWith.contains(oldCollisionObject)) {
            NamesOfObjectsCanCollideWith.remove(oldCollisionObject);
        }
    }

    /**
     * Fires all weapons currently equipped.
     * @return A list of all new shots.
     */
    public List<Interactable> fire() {
        List<Interactable> newShots = new ArrayList<Interactable>();
        for (WeaponObject weap : getMyWeapons()) {
            newShots.addAll(weap.fire());
        }
        return newShots;
    }

    /**
     * Returns the dimesions of the GameCharacter.
     */
    public Dimension getDimension() {
        return mySize;
    }

    /**
     * Changes the size of the GameCharacter to newSize.
     * @param newSize
     */
    public void setDimension(Dimension newSize) {
        mySize = newSize;
    }

    /**
     * Returns the center of the GameCharacter.
     */
    public Point getCenter () {
        return new Point(myPosition.x + Math.round(mySize.width/2),
                myPosition.y + Math.round(mySize.height/2));
    }

    /**
     * Returns the list of all objects the GameCharacter can collide with.
     */
    public ArrayList<String> getNamesOfInteractableCanCollideWith () {
        return (ArrayList<String>) NamesOfObjectsCanCollideWith;
    }

    /**
     * Sets the list of objects the GameCharacter can collide with.
     * @param names
     */
    public void setNamesOfInteractableCanCollideWith(List<String> names) {
        NamesOfObjectsCanCollideWith = names;
    }
}
